package com.guoxin.part2.chapter10;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 自定义类加载器
 *
 * @author guoxin
 * @date 2019/8/29
 */
public class MyClassLoader extends ClassLoader {
    private final static Path DEFAULT_CLASS_DIR = Paths.get("E:" + "classloader1");
    private final Path classDir;

    /**
     * 默认的class路径
     */
    public MyClassLoader() {
        super();
        this.classDir = DEFAULT_CLASS_DIR;
    }

    /**
     * @param classDir class路径
     */
    public MyClassLoader(String classDir) {
        super();
        this.classDir = Paths.get(classDir);
    }

    /**
     * @param classDir class路径
     * @param parent   父类加载器
     */
    public MyClassLoader(String classDir, ClassLoader parent) {
        super(parent);
        this.classDir = Paths.get(classDir);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 读取class的二进制数据
        byte[] classBytes = this.readClassBytes(name);
        if (classBytes == null || classBytes.length == 0) {
            throw new ClassNotFoundException("The class " + name + " not found.");
        }
        // 调用defineClass 方法定义 class
        return this.defineClass(name, classBytes, 0, classBytes.length);
    }

    /**
     * 将class文件读入内存
     *
     * @param name 类名
     * @return 字节数组
     * @throws ClassNotFoundException ClassNotFoundException
     */
    private byte[] readClassBytes(String name) throws ClassNotFoundException {
        String classPath = name.replace(".", "/");
        Path classFullPath = classDir.resolve(Paths.get(classPath + ".class"));
        if (!classFullPath.toFile().exists()) {
            throw new ClassNotFoundException("The class " + name + " not found.");
        }
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Files.copy(classFullPath, baos);
            return baos.toByteArray();
        } catch (IOException e) {
            throw new ClassNotFoundException("The class " + name + " not found.", e);
        }
    }

    @Override
    public String toString() {
        return "My ClassLoader";
    }
}
